package yxy.apple.http.response;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.StatusLine;
import org.apache.http.client.entity.GzipDecompressingEntity;
import org.apache.http.util.EntityUtils;

import yxy.apple.http.HTTPException;
import yxy.apple.util.http.HTTPProtocol;

public abstract class HTTPResponse<BodyContentType> {
	private StatusLine statusLine = null;
	private Header[] headers = null;
	private BodyContentType body = null;

	public void respond(HttpResponse response) throws HTTPException {
		try {
			this.statusLine = response.getStatusLine();
			this.headers = response.getAllHeaders();
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				boolean gzipped = false;
				for (Header header : headers) {
					String name = header.getName();
					String value = header.getValue();
					if (name != null && value != null && name.equalsIgnoreCase(HTTPProtocol.HeaderKey.ContentEncoding)
							&& value.equalsIgnoreCase(HTTPProtocol.ContentEncoding.GZip)) {
						gzipped = true;
						break;
					}
				}
				if (gzipped) {
					byte[] data = EntityUtils.toByteArray(new GzipDecompressingEntity(entity));
					this.body = this.decodeBody(data);
				} else {
					byte[] data = EntityUtils.toByteArray(entity);
					this.body = this.decodeBody(data);
				}
			}
		} catch (Exception e) {
			throw new HTTPException(e);
		}
	}

	public BodyContentType body() {
		return this.body;
	}

	public Header[] headers() {
		return this.headers;
	}

	public int statusCode() {
		return this.statusLine.getStatusCode();
	}

	public String statusReasonPhrase() {
		return this.statusLine.getReasonPhrase();
	}

	public ProtocolVersion statusProtocolVersion() {
		return this.statusLine.getProtocolVersion();
	}

	@Override
	public String toString() {
		StringBuffer buffer = new StringBuffer();
		buffer.append(this.statusLineToString(this.statusLine));
		buffer.append("\r\n");
		buffer.append(this.headersToString(this.headers));
		buffer.append("\r\n");
		String content = this.bodyToString(this.body);
		if (content != null) {
			buffer.append(content);
			buffer.append("\r\n");
		}
		return buffer.toString();
	}

	protected String statusLineToString(StatusLine line) {
		return line.toString();
	}

	protected String headersToString(Header[] headers) {
		StringBuffer buffer = new StringBuffer();
		for (Header header : headers) {
			String key = header.getName();
			String value = header.getValue();
			buffer.append(key);
			buffer.append(": ");
			buffer.append(value);
			buffer.append("\r\n");
		}
		return buffer.toString();
	}

	protected abstract String bodyToString(BodyContentType body);

	protected abstract BodyContentType decodeBody(byte[] body) throws HTTPException;
}
